package com.poetry.util;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.FieldCollapse;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.poetry.domain.dto.PoemDoc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightField;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightParameters;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ESUtil {
    public static final Integer MAX_SUGGESTIONS = 10;
    public NativeQuery buildSearchQuery(String query, String type, String dynasty, String author, Pageable pageable) {
        // 高亮设置
        HighlightParameters highlightParams = HighlightParameters.builder()
                .withPreTags(new String[]{"<em class='highlight'>"})
                .withPostTags(new String[]{"</em>"})
                .withRequireFieldMatch(false).build();
        List<HighlightField> highlightFields = Arrays.asList(
                new HighlightField("title"),
                new HighlightField("author"),
                new HighlightField("content")
        );
        Highlight highlight = new Highlight(highlightParams, highlightFields);
        HighlightQuery highlightQuery = new HighlightQuery(highlight, null);
        Function<BoolQuery.Builder, BoolQuery.Builder> fieldQueryBuilder = b -> {
            if (author == null || author.isEmpty()) {
                return b.should(s -> s.match(m -> m.field("title").query(query).boost(3.0f)))
                        .should(s -> s.match(m -> m.field("content").query(query).boost(2.0f)))
                        .should(s -> s.match(m -> m.field("author").query(query).boost(1.5f)));
            }
            if (type == null || type.isEmpty()) {
                // 默认搜索所有字段
                return b.must(s -> s.match(m -> m.field("author").query(author).boost(3.0f)))
                        .should(s -> s.match(m -> m.field("title").query(query).boost(3.0f)))
                        .should(s -> s.match(m -> m.field("content").query(query).boost(2.0f)))
                        .should(s -> s.match(m -> m.field("author").query(query).boost(1.5f)));
            }

            return switch (type.toLowerCase()) {
                case "author" ->
                    // 只搜索作者字段
                        b.must(m -> m.match(mt -> mt.field("author").query(query)))
                                .should(s -> s.match(mt -> mt.field("author").query(author)));
                case "title" ->
                    // 只搜索标题和内容字段
                        b.must(s -> s.match(m -> m.field("author").query(author).boost(3.0f)))
                                .should(s -> s.match(m -> m.field("title").query(query).boost(3.0f)))
                                .should(s -> s.match(m -> m.field("content").query(query).boost(2.0f)));
                case "content" ->
                    // 只搜索内容字段
                        b.must(s -> s.match(m -> m.field("author").query(author).boost(3.0f)))
                                .should(m -> m.match(mt -> mt.field("content").query(query)));
                default ->
                    // 其他情况使用默认搜索
                        b.must(s -> s.match(m -> m.field("author").query(author).boost(3.0f)))
                                .should(s -> s.match(m -> m.field("title").query(query).boost(3.0f)))
                                .should(s -> s.match(m -> m.field("content").query(query).boost(2.0f)))
                                .should(s -> s.match(m -> m.field("author").query(query).boost(1.5f)));
            };
        };
        NativeQueryBuilder builder = NativeQuery.builder()
                .withQuery(q -> q.bool(fieldQueryBuilder::apply))
                .withHighlightQuery(highlightQuery)
                .withPageable(pageable)
                .withFieldCollapse(new FieldCollapse.Builder()
                                .field("id").build());
        if (StringUtils.hasText(dynasty)) {
            Query filterQuery = Query.of(q -> q
                    .term(t -> t
                            .field("dynasty")
                            .value(dynasty)
                    )
            );
            builder.withFilter(filterQuery);
        }
        return builder.build();
    }

    public List<PoemDoc> processSearchHits(SearchHits<PoemDoc> searchHits) {
        return searchHits.getSearchHits().stream()
                .map(this::mapSearchHit)
                .collect(Collectors.toList());
    }

    private PoemDoc mapSearchHit(SearchHit<PoemDoc> hit) {
        PoemDoc poem = hit.getContent();
        // 处理高亮
        if (hit.getHighlightFields() != null) {
            if (hit.getHighlightFields().containsKey("title")) {
                poem.setHighlightedTitle(String.join(" ", hit.getHighlightFields().get("title")));
            }
            if (hit.getHighlightFields().containsKey("author")) {
                poem.setHighlightedAuthor(String.join(" ", hit.getHighlightFields().get("author")));
            }
            if (hit.getHighlightFields().containsKey("content")) {
                poem.setHighlightedContent(String.join(" ", hit.getHighlightFields().get("content")));
            }
        }

        return poem;
    }

    /**
     * 提取并合并多字段的建议结果
     */
    public List<String> extractAndMergeSuggestions(SearchResponse<PoemDoc> response, String prefix) {

        // 从响应中获取所有建议
        Map<String, String> uniqueSuggestions = new LinkedHashMap<>(MAX_SUGGESTIONS * 3);
        response.suggest().forEach((key, value) -> {
            log.info("Suggestion for {}: {}", key, value);
        });

        addFieldSuggestions(response, "title_suggest", uniqueSuggestions, prefix, MAX_SUGGESTIONS);
        addFieldSuggestions(response, "author_suggest", uniqueSuggestions, prefix, MAX_SUGGESTIONS);
        addFieldSuggestions(response, "content_suggest", uniqueSuggestions, prefix, MAX_SUGGESTIONS);

        // 返回去重后的列表
        return new ArrayList<>(uniqueSuggestions.keySet())
                .subList(0, Math.min(MAX_SUGGESTIONS, uniqueSuggestions.size()));
    }

    /**
     * 从特定建议器中提取建议
     */
    private void addFieldSuggestions(SearchResponse<PoemDoc> response,
                                     String suggestName,
                                     Map<String, String> uniqueMap,
                                     String prefix,
                                     int maxSize) {
        if (uniqueMap.size() >= maxSize) return;

        List<Suggestion<PoemDoc>> suggestions = response.suggest().get(suggestName);
        if (suggestions == null) return;

        for (Suggestion<PoemDoc> suggestion : suggestions) {
            if (suggestion.isCompletion()) {
                for (CompletionSuggestOption<PoemDoc> option : suggestion.completion().options()) {
                    String text = option.text();

                    // 智能去重：相同文本不同来源允许存在
                    String sourceType = getSourceType(suggestName);

                    // 如果文本相同但来源不同，标记为不同建议
                    String uniqueKey = text + "|" + sourceType;

                    if (!uniqueMap.containsKey(uniqueKey)) {
                        uniqueMap.put(uniqueKey, text);

                        // 达到目标数量时停止
                        if (uniqueMap.size() >= maxSize) return;
                    }
                }
            }
        }
    }
    private String getSourceType(String suggestName) {
        switch(suggestName) {
            case "title_suggest": return "标题";
            case "author_suggest": return "作者";
            case "content_suggest": return "内容";
            default: return "其他";
        }
    }
}
